#ifndef BOOST__THREAD__DETAILS__UNILOCK_INTERFACE_IMPL_HPP
#  define BOOST__THREAD__DETAILS__UNILOCK_INTERFACE_IMPL_HPP

// Copyright (C) 2004-2009
// Alex Turbov, Igor Veresov
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#  include <boost/thread/condition.hpp>
#  include <boost/thread/mutex.hpp>

#  include <boost/call_traits.hpp>

namespace boost { namespace details {

template <typename Scheduler>
class unilock_interface_impl : private Scheduler
{
public:
    typedef Scheduler scheduler_type;
    typedef typename scheduler_type::lock_params_type lock_params_type;
    typedef typename scheduler_type::unlock_params_type unlock_params_type;

protected:
    mutex m_mut;
    condition m_cond;

    typedef bool (unilock_interface_impl::*lock_func_t)(
        typename call_traits<lock_params_type>::param_type
      , int
      , mutex::scoped_lock&
      );

    bool lock_impl(typename call_traits<lock_params_type>::param_type p, int request_id, mutex::scoped_lock& l)
    {
        while (!scheduler_type::try_lock(p, request_id))
            m_cond.wait(l);
        return true;
    }
    bool try_lock_impl(typename call_traits<lock_params_type>::param_type p, int request_id, mutex::scoped_lock&)
    {
        return scheduler_type::try_lock(p, request_id);
    }

    bool lock_decorator(typename call_traits<lock_params_type>::param_type p, lock_func_t lf)
    {
        bool result = false;
        {
            mutex::scoped_lock l(m_mut);                   // may throw thread_resource_error
            int request_id;
            try
            {
                request_id = scheduler_type::assign_request_id(p);
            }
            catch (...)
            {
                throw thread_resource_error();
            }
            try
            {
                result = (this->*lf)(p, request_id, l);    // call decorated member function
            }
            catch (const thread_interrupted&)
            {
                try
                {
                    scheduler_type::unassign_request_id(p, request_id);
                }
                catch (...)
                {
                    throw thread_resource_error();
                }
            }
            try
            {
                scheduler_type::unassign_request_id(p, request_id);
            }
            catch (...)
            {
                throw thread_resource_error();
            }
        }
        m_cond.notify_all();
        return result;
    }

public:
    void lock_(typename call_traits<lock_params_type>::param_type p)
    {
        lock_decorator(p, &unilock_interface_impl::lock_impl);
    }
    bool try_lock_(typename call_traits<lock_params_type>::param_type p)
    {
        return lock_decorator(p, &unilock_interface_impl::try_lock_impl);
    }
    void unlock_(typename call_traits<unlock_params_type>::param_type p)
    {
        try
        {
            mutex::scoped_lock l(m_mut);                   // may throw thread_resource_error
            scheduler_type::unlock_(p);
        }
        catch (...)
        {
            throw thread_resource_error();
        }
        m_cond.notify_all();
    }
};

}}                                                         // namespace details, boost
#endif                                                     // #ifndef BOOST__THREAD__DETAILS__UNILOCK_INTERFACE_IMPL_HPP
